import 'dart:async';

import 'package:ble_printer/bean/ble_device.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'dart:convert';

import 'bean/ble_ret_data.dart';
import 'package:fluttertoast/fluttertoast.dart';
export 'bean/ble_device.dart';
export 'bean/ble_ret_data.dart';
export 'search_key_page.dart';
export 'utils/shared_utils.dart';

class BlePrinter {
  factory BlePrinter._init() {
    if (_singleton == null) {
      _singleton = BlePrinter._();
    }
    return _singleton!;
  }

  BlePrinter._();

  static BlePrinter get share => BlePrinter._init();
  static BlePrinter? _singleton;

  MethodChannel _channel = const MethodChannel('com.kayoxu.plugin.ble_printer');
  static const _eventChannel = const EventChannel('com.kayoxu.plugin/bleEvent');
  static const _eventChannelHome =
      const EventChannel('com.kayoxu.plugin/bleEventHome');
  static const _eventChannelBle =
      const EventChannel('com.kayoxu.plugin/bleEventBle');
  StreamSubscription? _subscription;
  StreamSubscription? _subscriptionHome;
  StreamSubscription? _subscriptionBle;

  Timer? _timer;

  bleInit({
    required Function? error,
    required Function? success,
  }) async {
    _timer = Timer(Duration(seconds: 50), () {
      _showToast('打印机初始化失败');
      error?.call();
    });

    var bleInit = await _jump<int>('bleInit');
    _timer?.cancel();
    _timer = null;
    if (bleInit == EventType.BLE_CONNECTED) {
      success?.call();
      return true;
    } else if (bleInit == EventType.BLE_CONNECTE_FAILED) {
      _showToast('打印机初始化失败');
      error?.call();
      return false;
    } else if (bleInit == EventType.BLE_DISCONNECTED) {
      _showToast('打印机已经断开连接');
      error?.call();
      return false;
    } else if (bleInit == EventType.BLE_CONNECTE_NODEVICE) {
      _showToast('请先连接打印机');
      error?.call();
      return false;
    } else if (bleInit == -1) {
      _showToast('请先连接打印机');
      error?.call();
      return false;
    }
    _showToast('打印机初始化失败');
    error?.call();
    return false;
  }

  void _showToast(String data) {
    Fluttertoast.showToast(
        msg: data,
        toastLength: Toast.LENGTH_LONG,
        gravity: ToastGravity.SNACKBAR,
        timeInSecForIosWeb: 2);
  }

  Future<String?> bleMac() async {
    return _jump<String>('bleMac');
  }

  Future<bool?> isBleConnected() async {
    return _jump<bool>('isBleConnected');
  }

  searchBle() async {
    _jump('searchBle');
  }

  stopSearchBle() async {
    _jump('stopSearchBle');
  }

  connectBle(BleDevice? data, {bool? autoOpenBle = true}) {
    _jump('connectBle', arguments: {
      'data': BlePrinter.share.toJson(data),
      'autoOpenBle': autoOpenBle
    });
  }

  disconnectBle() {
    _jump('disconnectBle');
  }

  printTitle(String data) {
    _jump('printTitle', arguments: {'data': data});
  }

  printData(String data) {
    _jump('printData', arguments: {'data': data});
  }

  printDashLine() {
    _jump('printDashLine');
  }

  printEmptyLine({int? lines}) {
    _jump('printEmptyLine', arguments: {'data': lines ?? 1});
  }

  printQrcode(String data, {int? height = 240}) {
    _jump('printQrcode', arguments: {'data': data, 'height': height});
  }

  printBarcode(String data,
      {int? height = 162, int? width = 2, bool? showCode = false}) {
    _jump('printBarcode', arguments: {
      'data': data,
      'height': height,
      'width': width,
      'showCode': showCode
    });
  }

  printText(
      {String? left,
      String? right,
      bool? bold = false,
      bool? doubleWidth = false,
      bool? doubleHeight = false,
      bool? underLine = false}) {
    _jump('printText', arguments: {
      'left': left,
      'right': right,
      'bold': bold,
      'doubleWidth': doubleWidth,
      'doubleHeight': doubleHeight,
      'underLine': underLine,
    });
  }

  void initState(ValueChanged? onEvent, Function? onError) {
    if (null == _subscription) {
      _subscription = _eventChannel
          .receiveBroadcastStream()
          .listen(onEvent, onError: onError);
    }
  }

  void dispose() {
    if (null != _subscription) {
      _subscription?.cancel();
      _subscription = null;
    }
  }

  void initStateHome(ValueChanged? onEvent, Function? onError) {
    if (null == _subscriptionHome) {
      _subscriptionHome = _eventChannelHome
          .receiveBroadcastStream()
          .listen(onEvent, onError: onError);
    }
  }

  void disposeHome() {
    if (null != _subscriptionHome) {
      _subscriptionHome?.cancel();
      _subscriptionHome = null;
    }
  }

  void initStateBle(ValueChanged? onEvent, Function? onError) {
    if (null == _subscriptionBle) {
      _subscriptionBle = _eventChannelBle
          .receiveBroadcastStream()
          .listen(onEvent, onError: onError);
    }
  }

  void disposeBle() {
    if (null != _subscriptionBle) {
      _subscriptionBle?.cancel();
      _subscriptionBle = null;
    }
  }

  Future<T?> _jump<T>(String method, {dynamic arguments}) {
    return _channel.invokeMethod<T>(method, arguments);
  }

  String toJson(dynamic data) {
    return jsonEncode(data);
  }

  dynamic getMapOrList(dynamic data) {
    if (data is String) {
      return json.decode(data);
    } else if (data is Map) {
      return data;
    } else {
      return {};
    }
  }
}
